package us.sunrisemorning.mykancolle.battle;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.RandomUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import us.sunrisemorning.mykancolle.mapdata.EnemyDeck;
import us.sunrisemorning.mykancolle.model.Deck;
import us.sunrisemorning.mykancolle.model.Ship;

public class Battle {
    private static final int[] EMPTY_SLOT = new int[] { -1, -1, -1, -1, -1 };
    private static final int[] EMPTY_KYOUKA = new int[] { 0, 0, 0, 0 };
    private static final int[] EMPTY_PARAM = new int[] { 0, 0, 0, 0 };

    private List<BattleShip> fship = new ArrayList<>();
    private List<BattleShip> eship = new ArrayList<>();

    private int fformation;
    private int eformation;
    // TODO:航向
    private int bformation;

    private String enemyDeckName;

    private long userId;

    public Battle(Deck deck, EnemyDeck edeck, long userId, int fformation) {
        this.fformation = fformation;
        this.eformation = edeck.getFormation();
        this.bformation = RandomUtils.nextInt(1, 5);
        this.enemyDeckName = edeck.getDeckName();
        this.userId = userId;

        Long[] fships = deck.getShip();
        for (Long shipId : fships) {
            if (shipId < 0) {
                continue;
            }
            Ship ship = Ship.dao.findById(shipId, userId);
            BattleShip bship = new BattleShip();
            bship.loadFShip(ship);
            fship.add(bship);
        }

        int[] eships = edeck.getEnemyDecks();
        for (int shipId : eships) {
            if (shipId < 0) {
                continue;
            }
            BattleShip bship = new BattleShip();
            bship.loadEShip(shipId);
            eship.add(bship);
        }
    }

    public JSONObject getDayBattleResult() {
        JSONObject result = new JSONObject();
        result.put("ship_ke", getShipKe());
        result.put("ship_lv", getShipLv());
        result.put("nowhps", getNowHps());
        result.put("maxhps", getMaxHps());
        result.put("eSlot", getESlot());
        result.put("eKyouka", getEKyoka());
        result.put("fParam", getShipParam(6, fship));
        result.put("eParam", getShipParam(6, eship));
        // TODO:索敌成功与否
        result.put("search", new int[] { 5, 5 });
        result.put("formation", new int[] { fformation, eformation, bformation });

        runKoukuBattle(result);
        runSupportBattle(result);
        runOpeningBattle(result);

        result.put("hourai_flag", new int[] { 1, 0, 0, 0 });
        result.put("hougeki1", runHougekiBattle());
        result.put("hougeki2", null);
        result.put("hougeki3", null);
        result.put("raigeki", null);

        result.put("midnight_flag", isEnemyAllDead() ? 0 : 1);
        return result;
    }

    // TODO:航空战
    private void runKoukuBattle(JSONObject result) {
        result.put("stage_flag", new int[] { 1, 0, 0 });
        JSONObject kouku = new JSONObject();
        kouku.put("plane_from", new int[][] { new int[] { -1 }, new int[] { -1 } });
        JSONObject stage1 = new JSONObject();
        stage1.put("f_count", 0);
        stage1.put("f_lostcount", 0);
        stage1.put("e_count", 0);
        stage1.put("e_lostcount", 0);
        stage1.put("disp_seiku", 1);
        stage1.put("touch_plane", new int[] { -1, -1 });
        kouku.put("stage1", stage1);
        result.put("kouku", kouku);
    }

    // TODO:支援舰队
    private void runSupportBattle(JSONObject result) {
        result.put("support_flag", 0);
        result.put("support_info", null);
    }

    // TODO:开幕雷击
    private void runOpeningBattle(JSONObject result) {
        result.put("opening_flag", 0);
        result.put("opening_atack", null);
    }

    // TODO:炮击战
    private JSONObject runHougekiBattle() {
        JSONObject result = new JSONObject();

        JSONArray atList = new JSONArray();
        atList.add(-1);
        JSONArray atType = new JSONArray();
        atType.add(-1);
        JSONArray dfList = new JSONArray();
        dfList.add(-1);
        JSONArray siList = new JSONArray();
        siList.add(-1);
        JSONArray clList = new JSONArray();
        clList.add(-1);
        JSONArray damage = new JSONArray();
        damage.add(-1);
        result.put("at_list", atList);
        result.put("at_type", atType);
        result.put("df_list", dfList);
        result.put("si_list", siList);
        result.put("cl_list", clList);
        result.put("damage", damage);

        List<BattleShip> order = new ArrayList<>();
        List<BattleShip> ftarget = new ArrayList<>();
        List<BattleShip> etarget = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            if (i < fship.size()) {
                BattleShip ship = fship.get(i);
                if (!ship.isDead()) {
                    order.add(ship);
                    ftarget.add(ship);
                }
            }
            if (i < eship.size()) {
                BattleShip ship = eship.get(i);
                if (!ship.isDead()) {
                    order.add(ship);
                    etarget.add(ship);
                }
            }
        }

        for (int i = 0; i < order.size(); i++) {
            BattleShip ship = order.get(i);
            if (ship.isDead()) {
                continue;
            }

            List<BattleShip> target = null;
            List<BattleShip> from = null;
            List<BattleShip> to = null;
            int fromDiff = 0;
            int toDiff = 0;
            if (ship.isFriend()) {
                target = etarget;
                from = fship;
                to = eship;
                fromDiff = 0;
                toDiff = 6;
            } else {
                target = ftarget;
                from = eship;
                to = fship;
                fromDiff = 6;
                toDiff = 0;
            }
            
            if (target.isEmpty()) {
                continue;
            }

            int at = from.indexOf(ship) + fromDiff + 1;
            BattleShip targetShip = target.get(RandomUtils.nextInt(0, target.size()));
            int df = to.indexOf(targetShip) + toDiff + 1;
            atList.add(at);
            atType.add(0);
            dfList.add(new int[] { df });
            siList.add(new int[] { ship.getSlot()[0] });

            boolean isHit = RandomUtils.nextInt(0, 10) > 1;
            int hitDamage = isHit ? Math.max(0, (ship.getParam()[0] - targetShip.getParam()[3])) : 0;

            clList.add(new int[] { isHit ? 1 : 0 });
            damage.add(new int[] { hitDamage });

            targetShip.setNowhp(targetShip.getNowhp() - hitDamage);
            if (targetShip.isDead()) {
                target.remove(targetShip);
            }
        }

        return result;
    }

    // TODO:雷击战
    private JSONObject runRaigekiBattle() {
        JSONObject result = new JSONObject();

        return result;
    }

    // TODO:保存战斗结果
    public void saveFship() {
        for (int i = 0; i < fship.size(); i++) {
            BattleShip bship = fship.get(i);
            Ship ship = Ship.dao.findFirst("select id,user,nowhp from Ship where id=? and user=?", bship.getId(), userId);
            ship.setNowhp(bship.getNowhp());
            ship.update();
        }
    }

    public int[] getShipKe() {
        int[] result = new int[] { -1, -1, -1, -1, -1, -1, -1 };
        for (int i = 0; i < eship.size(); i++) {
            result[i + 1] = eship.get(i).getId();
        }
        return result;
    }

    private int[] getShipLv() {
        int[] result = new int[] { -1, -1, -1, -1, -1, -1, -1 };
        for (int i = 0; i < eship.size(); i++) {
            result[i + 1] = eship.get(i).getLevel();
        }
        return result;
    }

    private int[] getNowHps() {
        int[] result = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
        for (int i = 0; i < fship.size(); i++) {
            result[i + 1] = fship.get(i).getNowhp();
        }
        for (int i = 0; i < eship.size(); i++) {
            result[i + 7] = eship.get(i).getNowhp();
        }
        return result;
    }

    private int[] getMaxHps() {
        int[] result = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
        for (int i = 0; i < fship.size(); i++) {
            result[i + 1] = fship.get(i).getMaxhp();
        }
        for (int i = 0; i < eship.size(); i++) {
            result[i + 7] = eship.get(i).getMaxhp();
        }
        return result;
    }

    private JSONArray getESlot() {
        JSONArray result = new JSONArray();
        for (int i = 0; i < 6; i++) {
            if (i <= (eship.size() - 1)) {
                result.add(eship.get(i).getSlot());
            } else {
                result.add(EMPTY_SLOT);
            }
        }
        return result;
    }

    private JSONArray getEKyoka() {
        JSONArray result = new JSONArray();
        for (int i = 0; i < 6; i++) {
            result.add(EMPTY_KYOUKA);
        }
        return result;
    }

    private JSONArray getShipParam(int size, List<BattleShip> ships) {
        JSONArray result = new JSONArray();
        for (int i = 0; i < size; i++) {
            if (i <= (ships.size() - 1)) {
                result.add(ships.get(i).getParam());
            } else {
                result.add(EMPTY_PARAM);
            }
        }
        return result;
    }

    private boolean isEnemyAllDead() {
        for (int i = 0; i < eship.size(); i++) {
            if (eship.get(i).getNowhp() > 0) {
                return false;
            }
        }
        return true;
    }

    public List<BattleShip> getFship() {
        return fship;
    }

    // 被击沉的敌舰数量
    public int getDests() {
        int count = 0;
        for (BattleShip ship : eship) {
            if (ship.isDead()) {
                count++;
            }
        }
        return count;
    }

    // 敌舰旗舰是否被击沉
    public int getDestsf() {
        return eship.get(0).isDead() ? 1 : 0;
    }

    public JSONObject getEnemyInfo() {
        JSONObject result = new JSONObject();
        result.put("level", "");
        result.put("rank", "");
        result.put("deck_name", enemyDeckName);
        return result;
    }
}
